//
// Created by feng on 19-3-31.
//
#include <cmath>
#include <iostream>

// #include "nlohmann/json.hpp"
#include "SceneConfiguration.h"

using namespace solar;

// #include "Utils.h"
// #include "ParaUtils.h"
// #include "Sun.h"
// #include "SunPosition.h"

// SceneConfiguration *SceneConfiguration::sceneConfigurationInstance;

// SceneConfiguration *SceneConfiguration::getInstance() {
//     if(sceneConfigurationInstance == nullptr){
//         sceneConfigurationInstance = new SceneConfiguration();
//     }
//     return sceneConfigurationInstance;
// }

// template <typename T>
// int set_field(T &field, std::string field_json_format, nlohmann::json &json){
//     if(json.find(field_json_format) != json.end()){
//         field = json[field_json_format];
//         return 1;
//     }
//     return 0;
// }

// template <typename T>
// int set_3field(T &field, std::string field_json_format, nlohmann::json &json){
//     if(json.find(field_json_format) != json.end()){
//         field.x = json[field_json_format][0];
//         field.y = json[field_json_format][1];
//         field.z = json[field_json_format][2];
//         return 1;
//     }
//     return 0;
// }

// int SceneConfiguration::loadConfiguration(std::string configuration_file_path) {
//     std::ifstream inputJsonFile(configuration_file_path);
//     if(inputJsonFile.fail()){
//         std::string error_message = "The file '" + configuration_file_path + "' doesn't exist";
//         std::cerr << error_message << std::endl;
//         throw std::runtime_error(error_message);
//     }
//     nlohmann::json json;

//     /**
//      * TODO: if the json file is invalid, please deal with the exception.
//      */
//     inputJsonFile >> json;

//     int ans = 0;
//     ans += set_field(sun_azimuth,"sun_azimuth",json);
//     ans += set_field(sun_altitude,"sun_altitude",json);
//     ans += set_field(dni, "dni", json);
//     ans += set_field(csr, "csr", json);
//     ans += set_field(num_sunshape_groups, "num_of_sunshape_groups", json);
//     ans += set_field(num_sunshape_lights_per_group, "num_per_sunshape_group", json);
//     ans += set_field(inverse_transform_sampling_groups, "inverse_transform_sampling_groups",
//     json); ans += set_field(receiver_pixel_length, "receiver_pixel_length", json); ans +=
//     set_field(disturb_std, "helio_disturb_std", json); ans += set_field(helio_pixel_length,
//     "helio_pixel_length", json); ans += set_field(reflected_rate, "helio_reflected_rate", json);

//     if(ans != num_of_fields){
//         printf("Noted: not all fields are set. You may need to check your configuration
//         file.\n");
//     }
//     return ans;
// }

auto SceneConfiguration::getSun_dir() -> float3&
{
    float altitude = getSunAltitude() / 180 * M_PI;
    float azimuth = getSunAzimuth() / 180 * M_PI;
    sun_dir.z = std::cos(altitude) * std::cos(azimuth);
    sun_dir.y = -std::sin(altitude);
    sun_dir.x = -std::cos(altitude) * std::sin(azimuth);

    // printf("sun %f %f %f\n", sun_dir.x, sun_dir.y, sun_dir.z);

    return sun_dir;
}

auto SceneConfiguration::getDni() const -> float { return dni; }
auto SceneConfiguration::getSunAltitude() const -> float
{
    // printf("sun_altitude=%f\n",sun_altitude);
    return sun_altitude;
}
auto SceneConfiguration::getSunAzimuth() const -> float
{
    // printf("sun_azimuth=%f\n",sun_azimuth);
    return sun_azimuth;
}
auto SceneConfiguration::getCsr() -> float
{
    // printf("csr=%f\n",csr);
    return csr;
}
auto SceneConfiguration::corr_Csr() -> float
{
    // if (csr<=0.1)
    //    csr=(-2.245e+03)*powf(csr,4.0f)+(5.207e+02)*powf(csr,3.0f)-(3.939e+01)*powf(csr,2.0f)+(1.891e+00)*csr+(8e-03);
    // else
    //     csr = 1.973*powf(csr,4.0f)-2.481*powf(csr,3.0f)+0.607*powf(csr,2.0f)+1.151*csr-0.020;
    // printf("csr=%f\n",csr);
    // tracer
    // csr =
    // 0.004733749294807862+csr*(4.716738065192151+csr*(-463.506669149804+csr*(24745.88727411664+csr*(-606122.7511711778
    // + 5521693.445014727 * csr))));
    //  printf("csr=%f\n",csr);
    return csr;
}
auto SceneConfiguration::getNum_sunshape_groups() const -> int { return num_sunshape_groups; }

auto SceneConfiguration::getNum_sunshape_lights_per_group() const -> int
{
    return num_sunshape_lights_per_group;
}

auto SceneConfiguration::getReceiver_pixel_length() const -> float { return receiver_pixel_length; }

auto SceneConfiguration::getDisturb_std() const -> float { return disturb_std; }

auto SceneConfiguration::getHelio_pixel_length() const -> float { return helio_pixel_length; }

auto SceneConfiguration::getReflected_rate() const -> float { return reflected_rate; }

auto SceneConfiguration::getInverse_transform_sampling_groups() const -> int
{
    return inverse_transform_sampling_groups;
}

void SceneConfiguration::setSunAzimuth(float sun_azimuth) { this->sun_azimuth = sun_azimuth; }
void SceneConfiguration::setSunAltitude(float sun_altitude) { this->sun_altitude = sun_altitude; }
void SceneConfiguration::setDni(float dni) { this->dni = dni; }
void SceneConfiguration::setCsr(float csr) { this->csr = csr; }
void SceneConfiguration::setNum_sunshape_groups(int num_sunshape_groups)
{
    this->num_sunshape_groups = num_sunshape_groups;
}
void SceneConfiguration::setNum_sunshape_lights_per_group(int num_sunshape_lights_per_group)
{
    this->num_sunshape_lights_per_group = num_sunshape_lights_per_group;
}
void SceneConfiguration::setInverse_transform_sampling_groups(int inverse_transform_sampling_groups)
{
    this->inverse_transform_sampling_groups = inverse_transform_sampling_groups;
}
void SceneConfiguration::setReceiver_pixel_length(float receiver_pixel_length)
{
    this->receiver_pixel_length = receiver_pixel_length;
}
void SceneConfiguration::setHelio_pixel_length(float helio_pixel_length)
{
    this->helio_pixel_length = helio_pixel_length;
}
void SceneConfiguration::setDisturbStd(float slope_error) { this->disturb_std = slope_error; }
void SceneConfiguration::setReflectedRate(float reflected_rate)
{
    this->reflected_rate = reflected_rate;
}

/**
 * ！！！！！！没写完，有几个参数不知道怎么设置？？？？？？
 */
// bool SceneConfiguration::loadConfiguration(std::shared_ptr<Scene> scene,
// std::shared_ptr<RayTracingParameter> simulation_paras_)
// {
//     auto sun_ptr = scene->getSun();
//     auto sun_position_ptr =
//     sun_ptr->getPara(toMemberName("sun_position")).value<std::shared_ptr<SunPosition>>();

//     sun_azimuth = sun_position_ptr->getPara(toMemberName("azimuth")).toFloat();
//     sun_altitude = sun_position_ptr->getPara(toMemberName("elevation")).toFloat();
//     dni = sun_position_ptr->getPara(toMemberName("irradiance")).toFloat();      //
//     ！！！！！！先暂时把irradiance设置为dni（不太清楚两个参数之间有什么区别，先这样设置）
//     // csr 要怎么设置？？？不同sunshape的参数不一样诶???要不加一个sunshape指针？？？
//     csr = 0.1;      // !!!!!!car暂时设置为0.1
//     num_sunshape_groups = simulation_paras_->readNumSunshapeGroups().toInt();
//     num_sunshape_lights_per_group = simulation_paras_->readNumSunshapeLightsPerGroup().toInt();
//     inverse_transform_sampling_groups =
//     simulation_paras_->readInverseTransformSamplingGroups().toInt(); receiver_pixel_length =
//     simulation_paras_->readPixelLength().toFloat(); helio_pixel_length =
//     simulation_paras_->readMicroheliostatLength().toFloat();
//     // disturb_std 需要从某个定日镜的材质中获得 !!!!!!
//     // reflected_rate 需要从某个定日镜的材质中获得!!!!!!!
//     return true;
// }

void SceneConfiguration::test()
{
    std::cout
        << "========================== test SceneConfiguration begin ========================\n";

    printf("\tsun_dir=(%f,%f,%f), dni = %f, azimuth=%f, altitude=%f, csr=%f, sigma=%f, "
           "sunshape_type=%d\n",
           sun_dir.x, sun_dir.y, sun_dir.z, dni, sun_azimuth, sun_altitude, csr, sigma,
           sunshape_type);
    printf("\tnum_sunshape_grou=%d, num_sunshape_lights_per_group=%d, "
           "inverse_transform_sampling_groups=%d\n",
           num_sunshape_groups, num_sunshape_lights_per_group, inverse_transform_sampling_groups);
    printf("\treceiver_pixel_length=%f, helio_pixel_length=%f, disturb_std=%f, eflected_rate=%f\n",
           receiver_pixel_length, helio_pixel_length, disturb_std, reflected_rate);

    std::cout
        << "========================== test SceneConfiguration end   ========================\n";
}
